﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
using System.Web;
using System.Data;

namespace WFBASE
{
    /*反射調用類*/
    public class Invoke
    {
        private List<String> asssemblyList = new List<string>();
        private List<String> typeList = new List<String>();

        private static Invoke invoker;

        /// <summary>
        /// 單例模式，所以設置成private，防止用於自行創建其實例
        /// </summary>
        private Invoke()
        {
            String assemblyStr = System.Configuration.ConfigurationManager.AppSettings["DLL"];          //取得web.config配置的程序集，可能有多個
            asssemblyList.AddRange(assemblyStr.Split(new char[] { ',' }));
            foreach (String assemblyName in asssemblyList)
            {
                Assembly asssembly = Assembly.Load(assemblyName);
                Type[] types = asssembly.GetTypes();
                foreach (Type t in types)
                {
                    if (t.IsClass && t.IsPublic)                    //只加入公共類類型
                        typeList.Add(t.FullName + "," + assemblyName);          //eg.  BusEWF.BusEntry,BusEWF
                }
            }
        }

        public static Invoke GetInvoker()
        {
            if (invoker == null)
                invoker = new Invoke();
            return invoker;
        }

        /// <summary>
        /// 處理參數
        /// </summary>
        /// <param name="MethodPara">反射方法對應參數</param>
        /// <param name="parameters">Ajax傳入JSON格式參數集</param>
        /// <returns></returns>
        public static object[] SetParameter(ParameterInfo[] MethodPara)
        {
            int length = MethodPara.Length;
            object[] result = new object[length];

            for (int i = 0; i < length; i++)
            {
                string key = MethodPara[i].Name;
                result[i] = Convert.ChangeType(Post.QueryValue(key), MethodPara[i].ParameterType);
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="className">類名</param>
        /// <param name="method">方法名</param>
        /// <param name="parameters">參數集</param>
        /// <returns></returns>
        public String invoke(String className, String method)
        {
            List<String> fullNames = typeList.FindAll(delegate(String fullNameWithAssemblyName)     //找出傳入的類的全限定名(eg CSharpLearn.Teacher,CSharpLearn)
            {
                String fullName = fullNameWithAssemblyName.Split(new char[] { ',' })[0];         //分隔類名和程序集名，取得類名(含命名空間)
                if (fullName.IndexOf(className) == -1)
                    return false;
                String[] tempFullName = fullName.Split(new char[] { '.' });
                String[] tempClassName = className.Split(new char[] { '.' });
                if (tempFullName.Length < tempClassName.Length)
                    return false;
                for (int i = tempFullName.Length - 1, j = tempClassName.Length - 1; i >= 0 && j >= 0; i--, j--)
                {
                    if (tempClassName[j] != tempFullName[i])
                        return false;
                }
                return true;
            });

            String classFullName;
            if (fullNames.Count == 0)
                throw new Exception("找不到類型名，請提供正確的類型名!");
            else if (fullNames.Count > 1)
                throw new Exception("找到多個類型名，請加入命名空間以縮小範圍");
            else
            {
                classFullName = fullNames[0];
            }
            Type t = Type.GetType(classFullName);
            MethodInfo methodInfo = t.GetMethod(method);
            Type returnType = methodInfo.ReturnType;
            object o = null;
            if (!methodInfo.IsStatic)            //如果要調用的方法不是靜態的，就創建實例；如果是靜態的，則保留null值。
                o = Activator.CreateInstance(t);

            object[] parameters = SetParameter(methodInfo.GetParameters());

            object ret = methodInfo.Invoke(o, parameters);
            if (ret != null)
            {
                if (returnType == typeof(DataTable))       //如果返回的是DataTable
                {
                    String result = NewConverter.WriteDataTable(ret as DataTable);          //轉化成json字符串
                    HttpContext.Current.Response.ContentType = "application/json";
                    return result;
                }
                else if (returnType == typeof(DataSet))    //如果返回的是DataSet
                {
                    String result = NewConverter.WriteDataSet(ret as DataSet);          //轉化成json字符串
                    HttpContext.Current.Response.ContentType = "application/json";
                    return result;
                }
                else
                    return ret.ToString();
            }
            else
                return "";
        }

    }
}
